home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / win / tkWin3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  15.5 KB  |  536 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkWin3d.c --
  3.  *
  4.  *    This file contains the platform specific routines for
  5.  *    drawing 3d borders in the Windows 95 style.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkWin3d.c 1.6 97/08/12 14:28:54
  13.  */
  14.  
  15. #include <tk3d.h>
  16. #include <tkWinInt.h>
  17.  
  18. /*
  19.  * This structure is used to keep track of the extra colors used by
  20.  * Windows 3d borders.
  21.  */
  22.  
  23. typedef struct {
  24.     TkBorder info;
  25.     XColor *light2ColorPtr; /* System3dLight */
  26.     XColor *dark2ColorPtr;  /* System3dDarkShadow */
  27. } WinBorder;
  28.  
  29.  
  30. /*
  31.  *----------------------------------------------------------------------
  32.  *
  33.  * TkpGetBorder --
  34.  *
  35.  *    This function allocates a new TkBorder structure.
  36.  *
  37.  * Results:
  38.  *    Returns a newly allocated TkBorder.
  39.  *
  40.  * Side effects:
  41.  *    None.
  42.  *
  43.  *----------------------------------------------------------------------
  44.  */
  45.  
  46. TkBorder *
  47. TkpGetBorder()
  48. {
  49.     WinBorder *borderPtr = (WinBorder *) ckalloc(sizeof(WinBorder));
  50.     borderPtr->light2ColorPtr = NULL;
  51.     borderPtr->dark2ColorPtr = NULL;
  52.     return (TkBorder *) borderPtr;
  53. }
  54.  
  55. /*
  56.  *----------------------------------------------------------------------
  57.  *
  58.  * TkpFreeBorder --
  59.  *
  60.  *    This function frees any colors allocated by the platform
  61.  *    specific part of this module.
  62.  *
  63.  * Results:
  64.  *    None.
  65.  *
  66.  * Side effects:
  67.  *    May deallocate some colors.
  68.  *
  69.  *----------------------------------------------------------------------
  70.  */
  71.  
  72. void
  73. TkpFreeBorder(borderPtr)
  74.     TkBorder *borderPtr;
  75. {
  76.     WinBorder *winBorderPtr = (WinBorder *) borderPtr;
  77.     if (winBorderPtr->light2ColorPtr) {
  78.     Tk_FreeColor(winBorderPtr->light2ColorPtr);
  79.     }
  80.     if (winBorderPtr->dark2ColorPtr) {
  81.     Tk_FreeColor(winBorderPtr->dark2ColorPtr);
  82.     }
  83. }
  84.  
  85. /*
  86.  *--------------------------------------------------------------
  87.  *
  88.  * Tk_3DVerticalBevel --
  89.  *
  90.  *    This procedure draws a vertical bevel along one side of
  91.  *    an object.  The bevel is always rectangular in shape:
  92.  *            |||
  93.  *            |||
  94.  *            |||
  95.  *            |||
  96.  *            |||
  97.  *            |||
  98.  *    An appropriate shadow color is chosen for the bevel based
  99.  *    on the leftBevel and relief arguments.  Normally this
  100.  *    procedure is called first, then Tk_3DHorizontalBevel is
  101.  *    called next to draw neat corners.
  102.  *
  103.  * Results:
  104.  *    None.
  105.  *
  106.  * Side effects:
  107.  *    Graphics are drawn in drawable.
  108.  *
  109.  *--------------------------------------------------------------
  110.  */
  111.  
  112. void
  113. Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
  114.     leftBevel, relief)
  115.     Tk_Window tkwin;        /* Window for which border was allocated. */
  116.     Drawable drawable;        /* X window or pixmap in which to draw. */
  117.     Tk_3DBorder border;        /* Token for border to draw. */
  118.     int x, y, width, height;    /* Area of vertical bevel. */
  119.     int leftBevel;        /* Non-zero means this bevel forms the
  120.                  * left side of the object;  0 means it
  121.                  * forms the right side. */
  122.     int relief;            /* Kind of bevel to draw.  For example,
  123.                  * TK_RELIEF_RAISED means interior of
  124.                  * object should appear higher than
  125.                  * exterior. */
  126. {
  127.     TkBorder *borderPtr = (TkBorder *) border;
  128.     int left, right;
  129.     Display *display = Tk_Display(tkwin);
  130.     TkWinDCState state;
  131.     HDC dc = TkWinGetDrawableDC(display, drawable, &state);
  132.     int half;
  133.  
  134.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  135.     TkpGetShadows(borderPtr, tkwin);
  136.     }
  137.  
  138.     switch (relief) {
  139.     case TK_RELIEF_RAISED:
  140.         left = (leftBevel)
  141.         ? borderPtr->lightGC->foreground
  142.         : borderPtr->darkGC->foreground;
  143.         right = (leftBevel)
  144.         ? ((WinBorder *)borderPtr)->light2ColorPtr->pixel
  145.         : ((WinBorder *)borderPtr)->dark2ColorPtr->pixel;
  146.         break;
  147.     case TK_RELIEF_SUNKEN:
  148.         left = (leftBevel)
  149.         ? ((WinBorder *)borderPtr)->dark2ColorPtr->pixel
  150.         : ((WinBorder *)borderPtr)->light2ColorPtr->pixel;
  151.         right = (leftBevel)
  152.         ? borderPtr->darkGC->foreground
  153.         : borderPtr->lightGC->foreground;
  154.         break;
  155.     case TK_RELIEF_RIDGE:
  156.         left = borderPtr->lightGC->foreground;
  157.         right = borderPtr->darkGC->foreground;
  158.         break;
  159.     case TK_RELIEF_GROOVE:
  160.         left = borderPtr->darkGC->foreground;
  161.         right = borderPtr->lightGC->foreground;
  162.         break;
  163.     case TK_RELIEF_FLAT:
  164.         left = right = borderPtr->bgGC->foreground;
  165.         break;
  166.     case TK_RELIEF_SOLID:
  167.         left = right = RGB(0,0,0);
  168.         break;
  169.     }
  170.     half = width/2;
  171.     if (leftBevel && (width & 1)) {
  172.     half++;
  173.     }
  174.     TkWinFillRect(dc, x, y, half, height, left);
  175.     TkWinFillRect(dc, x+half, y, width-half, height, right);
  176.     TkWinReleaseDrawableDC(drawable, dc, &state);
  177. }
  178.  
  179. /*
  180.  *--------------------------------------------------------------
  181.  *
  182.  * Tk_3DHorizontalBevel --
  183.  *
  184.  *    This procedure draws a horizontal bevel along one side of
  185.  *    an object.  The bevel has mitered corners (depending on
  186.  *    leftIn and rightIn arguments).
  187.  *
  188.  * Results:
  189.  *    None.
  190.  *
  191.  * Side effects:
  192.  *    None.
  193.  *
  194.  *--------------------------------------------------------------
  195.  */
  196.  
  197. void
  198. Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
  199.     leftIn, rightIn, topBevel, relief)
  200.     Tk_Window tkwin;        /* Window for which border was allocated. */
  201.     Drawable drawable;        /* X window or pixmap in which to draw. */
  202.     Tk_3DBorder border;        /* Token for border to draw. */
  203.     int x, y, width, height;    /* Bounding box of area of bevel.  Height
  204.                  * gives width of border. */
  205.     int leftIn, rightIn;    /* Describes whether the left and right
  206.                  * edges of the bevel angle in or out as
  207.                  * they go down.  For example, if "leftIn"
  208.                  * is true, the left side of the bevel
  209.                  * looks like this:
  210.                  *    ___________
  211.                  *     __________
  212.                  *      _________
  213.                  *       ________
  214.                  */
  215.     int topBevel;        /* Non-zero means this bevel forms the
  216.                  * top side of the object;  0 means it
  217.                  * forms the bottom side. */
  218.     int relief;            /* Kind of bevel to draw.  For example,
  219.                  * TK_RELIEF_RAISED means interior of
  220.                  * object should appear higher than
  221.                  * exterior. */
  222. {
  223.     TkBorder *borderPtr = (TkBorder *) border;
  224.     Display *display = Tk_Display(tkwin);
  225.     int bottom, halfway, x1, x2, x1Delta, x2Delta;
  226.     TkWinDCState state;
  227.     HDC dc = TkWinGetDrawableDC(display, drawable, &state);
  228.     int topColor, bottomColor;
  229.  
  230.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  231.     TkpGetShadows(borderPtr, tkwin);
  232.     }
  233.  
  234.     /*
  235.      * Compute a GC for the top half of the bevel and a GC for the
  236.      * bottom half (they're the same in many cases).
  237.      */
  238.  
  239.     switch (relief) {
  240.     case TK_RELIEF_RAISED:
  241.         topColor = (topBevel)
  242.         ? borderPtr->lightGC->foreground
  243.         : borderPtr->darkGC->foreground;
  244.         bottomColor = (topBevel)
  245.         ? ((WinBorder *)borderPtr)->light2ColorPtr->pixel
  246.         : ((WinBorder *)borderPtr)->dark2ColorPtr->pixel;
  247.         break;
  248.     case TK_RELIEF_SUNKEN:
  249.         topColor = (topBevel)
  250.         ? ((WinBorder *)borderPtr)->dark2ColorPtr->pixel
  251.         : ((WinBorder *)borderPtr)->light2ColorPtr->pixel;
  252.         bottomColor = (topBevel)
  253.         ? borderPtr->darkGC->foreground
  254.         : borderPtr->lightGC->foreground;
  255.         break;
  256.     case TK_RELIEF_RIDGE:
  257.         topColor = borderPtr->lightGC->foreground;
  258.         bottomColor = borderPtr->darkGC->foreground;
  259.         break;
  260.     case TK_RELIEF_GROOVE:
  261.         topColor = borderPtr->darkGC->foreground;
  262.         bottomColor = borderPtr->lightGC->foreground;
  263.         break;
  264.     case TK_RELIEF_FLAT:
  265.         topColor = bottomColor = borderPtr->bgGC->foreground;
  266.         break;
  267.     case TK_RELIEF_SOLID:
  268.         topColor = bottomColor = RGB(0,0,0);
  269.     }
  270.  
  271.     /*
  272.      * Compute various other geometry-related stuff.
  273.      */
  274.  
  275.     if (leftIn) {
  276.     x1 = x+1;
  277.     } else {
  278.     x1 = x+height-1;
  279.     }
  280.     x2 = x+width;
  281.     if (rightIn) {
  282.     x2--;
  283.     } else {
  284.     x2 -= height;
  285.     }
  286.     x1Delta = (leftIn) ? 1 : -1;
  287.     x2Delta = (rightIn) ? -1 : 1;
  288.     halfway = y + height/2;
  289.     if (topBevel && (height & 1)) {
  290.     halfway++;
  291.     }
  292.     bottom = y + height;
  293.  
  294.     /*
  295.      * Draw one line for each y-coordinate covered by the bevel.
  296.      */
  297.  
  298.     for ( ; y < bottom; y++) {
  299.     /*
  300.      * In some weird cases (such as large border widths for skinny
  301.      * rectangles) x1 can be >= x2.  Don't draw the lines
  302.      * in these cases.
  303.      */
  304.  
  305.     if (x1 < x2) {
  306.         TkWinFillRect(dc, x1, y, x2-x1, 1,
  307.         (y < halfway) ? topColor : bottomColor);
  308.     }
  309.     x1 += x1Delta;
  310.     x2 += x2Delta;
  311.     }
  312.     TkWinReleaseDrawableDC(drawable, dc, &state);
  313. }
  314.  
  315. /*
  316.  *----------------------------------------------------------------------
  317.  *
  318.  * TkpGetShadows --
  319.  *
  320.  *    This procedure computes the shadow colors for a 3-D border
  321.  *    and fills in the corresponding fields of the Border structure.
  322.  *    It's called lazily, so that the colors aren't allocated until
  323.  *    something is actually drawn with them.  That way, if a border
  324.  *    is only used for flat backgrounds the shadow colors will
  325.  *    never be allocated.
  326.  *
  327.  * Results:
  328.  *    None.
  329.  *
  330.  * Side effects:
  331.  *    The lightGC and darkGC fields in borderPtr get filled in,
  332.  *    if they weren't already.
  333.  *
  334.  *----------------------------------------------------------------------
  335.  */
  336.  
  337. void
  338. TkpGetShadows(borderPtr, tkwin)
  339.     TkBorder *borderPtr;    /* Information about border. */
  340.     Tk_Window tkwin;        /* Window where border will be used for
  341.                  * drawing. */
  342. {
  343.     XColor lightColor, darkColor;
  344.     int tmp1, tmp2;
  345.     XGCValues gcValues;
  346.  
  347.     if (borderPtr->lightGC != None) {
  348.     return;
  349.     }
  350.  
  351.     /*
  352.      * Handle the special case of the default system colors.
  353.      */
  354.  
  355.     if ((TkWinIndexOfColor(borderPtr->bgColorPtr) == COLOR_3DFACE)
  356.     || (TkWinIndexOfColor(borderPtr->bgColorPtr) == COLOR_WINDOW)) {
  357.     borderPtr->darkColorPtr = Tk_GetColor(NULL, tkwin,
  358.         Tk_GetUid("SystemButtonShadow"));
  359.     gcValues.foreground = borderPtr->darkColorPtr->pixel;
  360.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  361.     borderPtr->lightColorPtr = Tk_GetColor(NULL, tkwin,
  362.         Tk_GetUid("SystemButtonHighlight"));
  363.     gcValues.foreground = borderPtr->lightColorPtr->pixel;
  364.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  365.     ((WinBorder*)borderPtr)->dark2ColorPtr = Tk_GetColor(NULL, tkwin,
  366.         Tk_GetUid("System3dDarkShadow"));
  367.     ((WinBorder*)borderPtr)->light2ColorPtr = Tk_GetColor(NULL, tkwin,
  368.         Tk_GetUid("System3dLight"));
  369.     return;
  370.     } else {
  371.     darkColor.red = 0;
  372.     darkColor.green = 0;
  373.     darkColor.blue = 0;
  374.     ((WinBorder*)borderPtr)->dark2ColorPtr = Tk_GetColorByValue(tkwin,
  375.         &darkColor);
  376.     lightColor = *(borderPtr->bgColorPtr);
  377.     ((WinBorder*)borderPtr)->light2ColorPtr = Tk_GetColorByValue(tkwin, 
  378.         &lightColor);
  379.     }
  380.     
  381.     /*
  382.      * First, handle the case of a color display with lots of colors.
  383.      * The shadow colors get computed using whichever formula results
  384.      * in the greatest change in color:
  385.      * 1. Lighter shadow is half-way to white, darker shadow is half
  386.      *    way to dark.
  387.      * 2. Lighter shadow is 40% brighter than background, darker shadow
  388.      *    is 40% darker than background.
  389.      */
  390.  
  391.     if (Tk_Depth(tkwin) >= 6) {
  392.     /*
  393.      * This is a color display with lots of colors.  For the dark
  394.      * shadow, cut 40% from each of the background color components.
  395.      * For the light shadow, boost each component by 40% or half-way
  396.      * to white, whichever is greater (the first approach works
  397.      * better for unsaturated colors, the second for saturated ones).
  398.      */
  399.  
  400.     darkColor.red = (60 * (int) borderPtr->bgColorPtr->red)/100;
  401.     darkColor.green = (60 * (int) borderPtr->bgColorPtr->green)/100;
  402.     darkColor.blue = (60 * (int) borderPtr->bgColorPtr->blue)/100;
  403.     borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
  404.     gcValues.foreground = borderPtr->darkColorPtr->pixel;
  405.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  406.  
  407.     /*
  408.      * Compute the colors using integers, not using lightColor.red
  409.      * etc.: these are shorts and may have problems with integer
  410.      * overflow.
  411.      */
  412.  
  413.     tmp1 = (14 * (int) borderPtr->bgColorPtr->red)/10;
  414.     if (tmp1 > MAX_INTENSITY) {
  415.         tmp1 = MAX_INTENSITY;
  416.     }
  417.     tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->red)/2;
  418.     lightColor.red = (tmp1 > tmp2) ? tmp1 : tmp2;
  419.     tmp1 = (14 * (int) borderPtr->bgColorPtr->green)/10;
  420.     if (tmp1 > MAX_INTENSITY) {
  421.         tmp1 = MAX_INTENSITY;
  422.     }
  423.     tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->green)/2;
  424.     lightColor.green = (tmp1 > tmp2) ? tmp1 : tmp2;
  425.     tmp1 = (14 * (int) borderPtr->bgColorPtr->blue)/10;
  426.     if (tmp1 > MAX_INTENSITY) {
  427.         tmp1 = MAX_INTENSITY;
  428.     }
  429.     tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->blue)/2;
  430.     lightColor.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
  431.     borderPtr->lightColorPtr = Tk_GetColorByValue(tkwin, &lightColor);
  432.     gcValues.foreground = borderPtr->lightColorPtr->pixel;
  433.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  434.     return;
  435.     }
  436.  
  437.     if (borderPtr->shadow == None) {
  438.     borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
  439.         Tk_GetUid("gray50"));
  440.     if (borderPtr->shadow == None) {
  441.         panic("TkpGetShadows couldn't allocate bitmap for border");
  442.     }
  443.     }
  444.     if (borderPtr->visual->map_entries > 2) {
  445.     /*
  446.      * This isn't a monochrome display, but the colormap either
  447.      * ran out of entries or didn't have very many to begin with.
  448.      * Generate the light shadows with a white stipple and the
  449.      * dark shadows with a black stipple.
  450.      */
  451.  
  452.     gcValues.foreground = borderPtr->bgColorPtr->pixel;
  453.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  454.     gcValues.stipple = borderPtr->shadow;
  455.     gcValues.fill_style = FillOpaqueStippled;
  456.     borderPtr->darkGC = Tk_GetGC(tkwin,
  457.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  458.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  459.     gcValues.background = borderPtr->bgColorPtr->pixel;
  460.     borderPtr->lightGC = Tk_GetGC(tkwin,
  461.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  462.     return;
  463.     }
  464.  
  465.     /*
  466.      * This is just a measly monochrome display, hardly even worth its
  467.      * existence on this earth.  Make one shadow a 50% stipple and the
  468.      * other the opposite of the background.
  469.      */
  470.  
  471.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  472.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  473.     gcValues.stipple = borderPtr->shadow;
  474.     gcValues.fill_style = FillOpaqueStippled;
  475.     borderPtr->lightGC = Tk_GetGC(tkwin,
  476.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  477.     if (borderPtr->bgColorPtr->pixel
  478.         == WhitePixelOfScreen(borderPtr->screen)) {
  479.     gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  480.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  481.     } else {
  482.     borderPtr->darkGC = borderPtr->lightGC;
  483.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  484.     }
  485. }
  486.  
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * TkWinGetBorderPixels --
  491.  *
  492.  *    This routine returns the 5 COLORREFs used to draw a given
  493.  *    3d border.  
  494.  *
  495.  * Results:
  496.  *    Returns the colors in the specified array.
  497.  *
  498.  * Side effects:
  499.  *    May cause the remaining colors to be allocated.
  500.  *
  501.  *----------------------------------------------------------------------
  502.  */
  503.  
  504. COLORREF
  505. TkWinGetBorderPixels(tkwin, border, which)
  506.     Tk_Window tkwin;
  507.     Tk_3DBorder border;
  508.     int which;            /* One of TK_3D_FLAT_GC, TK_3D_LIGHT_GC,
  509.                  * TK_3D_DARK_GC, TK_3D_LIGHT2, TK_3D_DARK2 */
  510. {
  511.     WinBorder *borderPtr = (WinBorder *) border;
  512.     
  513.     if (borderPtr->info.lightGC == None) {
  514.     TkpGetShadows(&borderPtr->info, tkwin);
  515.     }
  516.     switch (which) {
  517.     case TK_3D_FLAT_GC:
  518.         return borderPtr->info.bgColorPtr->pixel;
  519.     case TK_3D_LIGHT_GC:
  520.         if (borderPtr->info.lightColorPtr == NULL) {
  521.         return WhitePixelOfScreen(borderPtr->info.screen);
  522.         }
  523.         return borderPtr->info.lightColorPtr->pixel;
  524.     case TK_3D_DARK_GC:
  525.         if (borderPtr->info.darkColorPtr == NULL) {
  526.         return BlackPixelOfScreen(borderPtr->info.screen);
  527.         }
  528.         return borderPtr->info.darkColorPtr->pixel;
  529.     case TK_3D_LIGHT2:
  530.         return borderPtr->light2ColorPtr->pixel;
  531.     case TK_3D_DARK2:
  532.         return borderPtr->dark2ColorPtr->pixel;
  533.     }
  534.     return 0;
  535. }
  536.